#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "config.h"
#include "auth.h"
#include "network.h"
#include "message.h"

//初始化
int client_socket = -1;// 客户端套接字文件描述符

/**
 *  客户端程序的主函数，负责初始化、连接服务器、用户认证和消息收发。
 * 
 * 该函数首先读取客户端配置文件，创建套接字并连接到服务器。
 * 接着进入认证循环，处理用户的注册、登录和退出操作。
 * 认证成功后，创建一个线程用于接收服务器消息，
 * 主线程则进入消息发送循环，处理用户输入并发送消息，直到用户输入退出命令。
 * 
 *  return int 程序退出状态码，正常退出返回 0，异常退出返回非 0 值。
 */
int main() {
    // 客户端配置结构体，用于存储从配置文件读取的配置信息
    ClientConfig client_config;
    // 服务器地址结构体，用于存储服务器的网络地址信息
    struct sockaddr_in server_addr;
    // 线程 ID，用于标识接收消息的线程
    pthread_t thread_id;
    // 消息缓冲区，用于存储用户输入的消息和服务器响应
    char message[BUFFER_SIZE];
    // 用户在认证菜单中的选择
    int choice;

    // 读取配置文件
    read_client_config(&client_config);
    // 打印客户端配置信息，包括服务器 IP 地址和端口号
    printf("客户端配置: ServerIP=%s , ServerPort=%d\n", 
           client_config.server_ip , client_config.server_port);

    // 创建套接字，使用 IPv4 协议和 TCP 传输协议
    client_socket = socket(AF_INET, SOCK_STREAM, 0);
    // 检查套接字创建是否失败
    if (client_socket == -1) {
        // 若失败，打印错误信息并退出程序
        perror("套接字创建失败");
        exit(EXIT_FAILURE);
    }

    // 初始化服务器地址结构体
    memset(&server_addr, 0, sizeof(server_addr));
    // 设置地址族为 IPv4
    server_addr.sin_family = AF_INET;
    // 将服务器 IP 地址从点分十进制转换为网络字节序
    server_addr.sin_addr.s_addr = inet_addr(client_config.server_ip);
    // 将服务器端口号从主机字节序转换为网络字节序
    server_addr.sin_port = htons(client_config.server_port);

    // 连接到服务器
    if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        // 若连接失败，打印错误信息，关闭套接字并退出程序
        perror("连接服务器失败");
        close(client_socket);
        exit(EXIT_FAILURE);
    }

    // 打印连接成功信息
    printf("已连接到服务器%s : %d\n", client_config.server_ip , client_config.server_port);

    // 认证循环，直到用户认证成功
    while (!is_authenticated) {
        // 显示认证菜单
        show_auth_menu();
        // 从标准输入读取用户选择
        fgets(message, sizeof(message), stdin);
        // 将用户选择转换为整数
        choice = atoi(message);
        
        // 根据用户选择执行相应操作
        switch (choice) {
            case 1: // 注册
                // 处理用户注册请求
                handle_register(client_socket);
                break;
                
            case 2: // 登录
                // 处理用户登录请求
                handle_login(client_socket);
                break;
                
            case 3: // 退出
                // 向服务器发送退出命令
                send(client_socket, "/exit", 5, 0);
                // 关闭套接字
                close(client_socket);
                // 打印断开连接信息
                printf("已断开连接\n");
                return 0;
                
            default:
                // 若用户输入无效，提示用户重新输入
                printf("无效选择，请重新输入\n");
        }
    }

    // 创建线程用于接收服务器消息
    //pthread_create函数用于创建一个新线程
    //&thread_id：指向线程标识符的指针，用于存储新线程的ID
    //NULL：线程属性，通常为NULL表示使用默认属性
    //receive_messages：线程函数，新线程将执行该函数
    //(void *)&client_socket：传递给线程函数的参数
    //返回值：若线程创建成功，返回0；若线程创建失败，返回错误码
    if (pthread_create(&thread_id, NULL, receive_messages, (void *)&client_socket) != 0) {
        // 若线程创建失败，打印错误信息，关闭套接字并退出程序
        perror("创建线程失败");
        close(client_socket);
        exit(EXIT_FAILURE);
    }
    // 将线程设置为分离状态，线程结束后自动释放资源
    pthread_detach(thread_id);

    // 发送消息循环
    while (1) {
        // 根据是否处于私聊模式打印不同的提示信息
        if (in_private_mode) {
            printf("[私聊:%s] ", private_target);
        } else {
            printf("[群聊] ");
        }
        
        // 清空消息缓冲区
        memset(message, 0, BUFFER_SIZE);
        // 从标准输入读取用户输入的消息
        if (fgets(message, BUFFER_SIZE, stdin) == NULL){
            printf("读取输入失败\n");
            continue;
        }
        // 去除消息末尾的换行符
        // 从字符串开头开始查找，统计连续不包含换行符的字符数
        // 若存在换行符，返回其在字符串中的索引位置
        // 若不存在换行符，返回字符串的长度
        //返回值定位到message数组中对应的位置，即换行符的位置
        //将这个位置赋值为0，即\0，实现删除换行符
        message[strcspn(message, "\n")] = 0;

        // 处理消息发送到服务器
        send_message(client_socket, message);//函数定义在message.h
        
        // 检查用户是否输入退出命令
        if (strcmp(message, "exit") == 0) {
            
            // 若输入退出命令，跳出循环
            break;
        }
    }

    // 关闭套接字
    close(client_socket);
    // 打印断开连接信息
    printf("已断开连接\n");
    return 0;
}